/*
 * Copyright (C) 2006-2015
 * 版权所有者为北京捷越联合信息咨询有限公司。本系统是商用软件,未经授权擅自复制或传播本程序的部分或全部将是非法的。
 * @title: DEBXCalculate.java
 * @package com.jy.modules.cims.component.credit.creditor.common
 * @author zhaox
 * @date 2015-7-21 下午5:35:08
 * @version v1.00
 * @description: TODO(用一句话描述该文件做什么)
 */

package com.jy.modules.cims.component.credit.creditor.common;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.jy.modules.cims.common.sysUtils.DateTimeUtils;
import com.jy.modules.cims.component.credit.credit.ICreditFee;
import com.jy.modules.cims.data.common.dto.TCMmCostPlanDTO;
import com.jy.modules.cims.data.common.dto.TCMmCreditSettleParamDTO;
import com.jy.modules.cims.data.dao.RepaymentPlanDao;
import com.jy.modules.cims.data.dto.credit.CreditFeeDto;
import com.jy.modules.cims.data.dto.credit.CreditFeeParamDto;
import com.jy.modules.cims.data.dto.credit.CreditSettleParam;

/**
 * 等额本息规则生成结算计划.
 * 
 * @classname: DEBXCalculate
 * @description: TODO(这里用一句话描述这个类的作用)
 */
@Service("com.jy.modules.cims.component.credit.creditor.common.DEBXCalculate")
public class DEBXCalculate implements ICalculateSettlePlan {

    @Autowired
    @Qualifier("com.jy.modules.cims.component.credit.credit.CreditFeeImpl")
    private ICreditFee iCreditFee;

    @Autowired
    private RepaymentPlanDao repaymentPlanDao;

   // private java.text.DecimalFormat df = new java.text.DecimalFormat("0.00");

    /*
     * (非 Javadoc) <p>title: calculate</p> <p>description: </p>
     * 
     * @param creditSettleParam
     * 
     * @return
     * 
     * @see
     * com.jy.modules.cims.component.credit.creditor.common.ICalculateSettlePlan
     * #calculate(com.jy.modules.cims.data.dto.credit.CreditSettleParam)
     */

    @Override
    public List<Map<String, Object>> calculate(CreditSettleParam creditSettleParam) throws Exception {
        // 初始化结算计划
        // 全额匹配01
        // 本金匹配02
        // 全额返还03
        String flag = creditSettleParam.getFlag();
        int term = creditSettleParam.getTerm();
        int surplusTerm = creditSettleParam.getSurplusTerm();
        // 从第几期开始生成结算计划
        int beginTerm = term - surplusTerm + 1;
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        // 设置首次还款日的日历
        Calendar calendar = Calendar.getInstance();
        Date date = creditSettleParam.getRepayStartDate();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, date.getDate());
        // 月还金额// 结算金额,只计算一次
        BigDecimal amt = calculateSettleAmt(creditSettleParam);
        
        TCMmCreditSettleParamDTO tCMmCreditSettleParamDTO = null;
        TCMmCostPlanDTO tCMmCostPlanDTO = null;
        HashMap<String, Object> map = null;
        
        // 标识结算计划第几期
        int j = 1;
        for (int i = 1; i <= term; i++) {
            // if (i == 1) {
            // amt = calculateSettleAmt(creditSettleParam);
            // }
            // 设置剩余期数
            creditSettleParam.setTerm(creditSettleParam.getTerm() - 1);
            // 结算利息
            BigDecimal interestAmt = interestAmt(creditSettleParam, creditSettleParam.getContractAmt());
            // 结算本金
            BigDecimal principalAmt = principalAmt(amt, interestAmt);
            // 设置下期还款后的剩余本金
            creditSettleParam.setContractAmt(creditSettleParam.getContractAmt().subtract(principalAmt));
            // 第一个还款日不需要加月，就是传过来的时间
            if (i > 1) {
                calendar.add(Calendar.MONTH, 1);
            }
            if (i >= beginTerm) {
                map = new HashMap<String, Object>();
                // 如果是历史数据，期数正常；新增数据，期数从1开始
                if ("0".equals(flag)) {
                    map.put("term", i);
                } else {
                    map.put("term", j);
                }
                map.put("must_amount", principalAmt);
                map.put("must_accrual", interestAmt);
                map.put("this_repay_sum", amt);
                map.put("credit_code", creditSettleParam.getCreditCode());
                map.put("transfer_id", creditSettleParam.getTransferId());
               // map.put("start_date", DateUtil.formatDateString("yyyyMMdd", calendar.getTime()));
                map.put("start_date", DateTimeUtils.formatDate(calendar.getTime(), DateTimeUtils.DEFAULT_DATE_TIME_FORMAT));
                map.put("validate_state", "1");
                // 匹配金额
                tCMmCreditSettleParamDTO = new TCMmCreditSettleParamDTO();
                tCMmCreditSettleParamDTO.setReplaceType(creditSettleParam.getmReplaceType());
                tCMmCostPlanDTO = new TCMmCostPlanDTO();
                tCMmCostPlanDTO.setMustAmount(principalAmt);// 应还本
                tCMmCostPlanDTO.setMustAccrual(interestAmt);// 应还息
                CreditFeeDto creditFeeDto = iCreditFee.getSettleInfo(tCMmCreditSettleParamDTO, tCMmCostPlanDTO);
                map.put("match_amount", creditFeeDto.getMatchAmount());
                map.put("return_amount", creditFeeDto.getReturnAmount());
                list.add(map);
                j++;
            }
        }
        
        tCMmCreditSettleParamDTO = null;
        tCMmCostPlanDTO = null;
        map = null;
        
        return list;
    }

    /**
     * @throws Exception 
     * 计算结算金额
     * 
     * @title: calculateSettleAmt
     * @author
     * @description:
     * @date 2015-7-21 上午10:04:43
     * @param creditSettleParam
     * @return
     * @throws
     */
    public BigDecimal calculateSettleAmt(CreditSettleParam creditSettleParam) throws Exception {
        BigDecimal totalmoney = creditSettleParam.getContractAmt();
        BigDecimal monthactive = creditSettleParam.getRate();
        if (monthactive == null)
            throw new Exception(creditSettleParam.getCreditCode() + "," + creditSettleParam.getContractCode()
                    + ",月利率为空");
        int totalmonth = creditSettleParam.getTerm();
        // 结算金额
        BigDecimal x = (new BigDecimal("1").add(monthactive)).pow(totalmonth).subtract(new BigDecimal("1"));
        BigDecimal money = totalmoney.multiply(monthactive)
                .multiply((new BigDecimal("1").add(monthactive)).pow(totalmonth)).divide(x, 2);
        return money.setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 计算结算利息
     * 
     * @title: interestAmt
     * @author
     * @description:
     * @date 2015-7-21 上午10:04:40
     * @param creditSettleParam
     * @param lastPrincipalMoney 上期月还后的本金
     * @return
     * @throws
     */
    public BigDecimal interestAmt(CreditSettleParam creditSettleParam, BigDecimal lastPrincipalMoney) {
        BigDecimal monthinterestmoney = lastPrincipalMoney.multiply(creditSettleParam.getRate());
        return monthinterestmoney.setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 计算结算本金
     * 
     * @title: principalAmt
     * @author
     * @description:
     * @date 2015-7-21 上午10:04:37
     * @param money 月结金额
     * @param monthinterestmoney 结算利息
     * @return
     * @throws
     */
    public BigDecimal principalAmt(BigDecimal money, BigDecimal monthinterestmoney) {
        BigDecimal principalmoney = money.subtract(monthinterestmoney);
        return principalmoney;
    }

    /**
     * 应匹配金额
     * 
     * @title: matchAmt
     * @author
     * @description:
     * @date 2015-7-23 上午10:27:51
     * @param creditSettleParam
     * @return
     * @throws
     */
    public BigDecimal matchAmt(CreditSettleParam creditSettleParam) {
        // 应匹配金额=∑▒持有债权(结算本金)
        return new BigDecimal(1);
    }


    /**
     * @throws Exception 
     * 更新历史结算计划，提前结清部分
     * 
     * @title: calculateHis
     * @author
     * @description:
     * @date 2015-8-14 上午10:59:49
     * @param creditSettleParam
     * @return
     * @throws
     */
    public List calculateHis(CreditSettleParam creditSettleParam, String currentDate, int termHis, String mReplaceType) throws Exception {
        // 初始化结算计划
        // 全额匹配01
        // 本金匹配02
        // 全额返还03
        String flag = creditSettleParam.getFlag();
        int term = creditSettleParam.getTerm();
        int surplusTerm = creditSettleParam.getSurplusTerm();
        // 从第几期开始生成结算计划
        int beginTerm = term - surplusTerm + 1;
        List<Map<Object, Object>> list = new ArrayList<Map<Object, Object>>();
        // 设置首次还款日的日历
        Calendar calendar = Calendar.getInstance();
        Date date = creditSettleParam.getRepayStartDate();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, date.getDate());
        // 结算金额
        BigDecimal amt = calculateSettleAmt(creditSettleParam);
        // 标识结算计划第几期
        int j = 1;
        for (int i = 1; i <= term; i++) {
            // 设置剩余期数
            creditSettleParam.setTerm(creditSettleParam.getTerm() - 1);
            // 结算利息
            BigDecimal interestAmt = interestAmt(creditSettleParam, creditSettleParam.getContractAmt());
            // 结算本金
            BigDecimal principalAmt = principalAmt(amt, interestAmt);
            // 设置下期还款后的剩余本金
            creditSettleParam.setContractAmt(creditSettleParam.getContractAmt().subtract(principalAmt));
            // 第一个还款日不需要加月，就是传过来的时间
            if (i > 1) {
                calendar.add(Calendar.MONTH, 1);
            }
            HashMap<Object, Object> map = new HashMap<Object, Object>();
            // 如果是历史数据，期数正常；新增数据，期数从1开始
            if ("0".equals(flag)) {
                map.put("term", i);
            } else {
                map.put("term", j);
            }
            map.put("must_amount", principalAmt);
            map.put("must_accrual", interestAmt);
            map.put("this_repay_sum", amt);
            map.put("credit_code", creditSettleParam.getCreditCode());
            map.put("transfer_id", creditSettleParam.getTransferId());
            map.put("start_date", DateTimeUtils.formatDate(new Date(), "yyyyMMdd"));
            map.put("validate_state", "1");
            if (i >= Integer.valueOf(currentDate).intValue())
                list.add(map);
            j++;

            // if (i == termHis) {// 当期
            // if ("01".equals(mReplaceType)) {
            // matchAmt = matchAmt.add(amt);
            // returnAmt = new BigDecimal(0);
            // }// 本金匹配
            // else if ("02".equals(mReplaceType)) {
            // matchAmt = matchAmt.add(principalAmt);
            // returnAmt = interestAmt;
            // }// 全额返还
            // else if ("03".equals(mReplaceType)) {
            // matchAmt = new BigDecimal(0);
            // returnAmt = returnAmt.add(amt);
            // }
            // }
            // if (i > termHis) {// 剩余每期
            // if ("01".equals(mReplaceType)) {
            // matchAmt = matchAmt.add(amt);
            // }// 本金匹配
            // else if ("02".equals(mReplaceType)) {
            // matchAmt = matchAmt.add(principalAmt);
            // }// 全额返还
            // else if ("03".equals(mReplaceType)) {
            // matchAmt = new BigDecimal(0);
            // returnAmt = returnAmt.add(principalAmt);
            // }
            // }
            // 匹配金额
            // map.put("match_amount", matchAmt);
            // map.put("return_amount", returnAmt);
        }
        for (Map m : list) {
            repaymentPlanDao.updateSettlePlan1(m);
        }
        CreditFeeParamDto creditFeeParamDto = new CreditFeeParamDto();
        creditFeeParamDto.setContractCode(creditSettleParam.getContractCode());
        creditFeeParamDto.setTransferId(creditSettleParam.getTransferId());
        creditFeeParamDto.setCurrentTime(new Long(currentDate));
        creditFeeParamDto.setSettleStatus("01");
        CreditFeeDto creditFeeDto = iCreditFee.getAbnormalSettleInfo(creditFeeParamDto);
        Map map = new HashMap();
        map.put("credit_code", creditSettleParam.getCreditCode());
        map.put("transfer_id", creditSettleParam.getTransferId());
        map.put("term", currentDate);
        map.put("match_amount", creditFeeDto.getMatchAmount());
        map.put("return_amount", creditFeeDto.getReturnAmount());
        repaymentPlanDao.updateSettlePlan(map);
        return list;
    }
}
